home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / CopyBitsQuickly.c < prev    next >
Text File  |  1996-03-28  |  30KB  |  756 lines

  1. /*
  2. CopyBitsQuickly.c
  3.  
  4. CopyBitsQuickly.c is a dumb substitute for CopyBits that ignores the color
  5. tables and palettes, simply copying the raw pixels without any translation. It's
  6. for doing animations. (Try the demo Sandstorm.) Besides copying images, it can
  7. also add or multiply them. At one time it copied much faster than CopyBits did,
  8. but the latest timing (under System 7), by TimeVideo, indicates that they are of
  9. approximately equal speed.
  10.  
  11. Apple's CopyBits is an Apple Macintosh Toolbox routine for copying images, and
  12. is documented in Inside Macintosh Volumes I,V, and VI, and New Inside Macintosh:
  13. "Imaging with QuickDraw". CopyBitsQuickly does not cause the Memory Manager to
  14. move memory, and thus may be used in a VBL task.
  15.  
  16. I suggest that you use the higher-level interface provided by
  17. the VideoToolbox CopyWindows.c, which saves you from getting your hands dirty
  18. messing with pixmaps. You can just deal with windows and GWorlds.
  19.  
  20. The returned value is nonzero if an error occurred.
  21.  
  22. CopyBitsQuickly supports four modes:
  23. • srcCopy copies the source to the destination.
  24. • addOver adds the source to the destination. Both must have 8-bit pixels.
  25. Overflow is ignored.
  26. • addOverParallel adds the source to the destination (4 bytes at a time), i.e.
  27. parallel addition. Overflow may carry over into neighboring pixels within the image.
  28. Supports all pixel sizes.
  29. • mulOver causes the source and destination to be multiplied, pixel by pixel. Both
  30. must have 8-bit pixels. After multiplication, the product is divided by 128 and
  31. stored in the destination. Overflow is ignored. All the arithmetic is unsigned.
  32.  
  33. RESTRICTIONS:
  34. • srcBits and dstBits must both have the same number of bits/pixel.
  35. • dstRect and srcRect must have the same size.
  36. • mode must be either srcCopy, addOver, addOverParallel, or mulOver.
  37. • maskRgn must be NULL.
  38. • If mode is addOver or mulOver then the pixel size must be 8 bits.
  39. • If CopyBitsQuickly detects a violation of any of these restrictions it will return
  40. a nonzero value, indicating that an error occured.
  41.  
  42. RETURNED VALUE:
  43. 0 Success.
  44. 1 Illegal srcMode (only srcCopy, addOver, and mulOver are allowed). 
  45. 2 maskRgn!=NULL.
  46. 3 Source and destination rects are of unequal size.
  47. 4 After clipping there were no pixels to copy, or RectToAddress couldn't resolve 
  48.     address of source or destination.
  49. 5 Source and destination have unequal pixel sizes.
  50. 6 We need 32-bit addressing but it's not available.
  51. 7 This mode requires 8-bit pixels and the supplied pixel size is not 8 bits.
  52.  
  53. ACKNOWLEDGEMENTS:
  54. I learned the trick of using a switch() to jump into a loop from Bill Karsh's solution
  55. to the April 1994 MacTech Programmer's Challenge.
  56.  
  57. LIMITATIONS:
  58. • If a Rect extends across multiple screens, only as much of the upper-left of
  59. the Rect that's on one device will be used. The rest is clipped off.
  60. • When accessing a screen, CopyBitsQuickly() ought to, but doesn't, call
  61. ShieldCursor() to remove the cursor from the part of the screen it's reading or
  62. writing. Calling ShieldCursor would also have the desirable side effect of
  63. informing nonstandard video devices, like the Radius PowerView, that the screen
  64. has been updated. (NOTE: CopyWindows does this for you before calling CopyBitsQuickly.)
  65.  
  66. NOTE: For highest speed you should choose your srcRectPtr & dstRectPtr so that
  67. the first point moved to and from each row begins at a memory address that is a
  68. multiple of 4 bytes. The effect on speed is substantial, about 25%.
  69.  
  70. NOTE: If your computer boots in 24-bit mode, as set by the Memory Control Panel,
  71. then the THINK C Debugger will crash if it's activated while you've temporarily
  72. switched into 32-bit mode. So don't put any breakpoints in any section of code
  73. that's bracketed by calls to SwapMMUMode() unless your computer booted up in
  74. 32-bit mode. If your computer boots in 32-bit mode then the calls to SwapMMUMode
  75. do nothing, and you can put Debugger breakpoints anywhere.
  76.  
  77. BlockMoveData & BlockMoveDataUncached
  78.  
  79. For highest possible speed, CopyBitsQuickly.c, if possible, now uses Apple's 
  80. BlockMoveDataUncached() on PowerPC Macs or BlockMoveData() on 68k. For discussion
  81. see "Fast blitting.doc" in the Notes folder.
  82.  
  83. BlockMoveDataUncached is new, available only on the PowerPC Macs. You can't use
  84. BlockMoveData on PowerPC macs to copy to video, because video is uncached and
  85. for some reason an instruction used by BlockMoveData runs extremely slowly when
  86. writing to uncached memory. BlockMoveDataUncached is designed specifically for
  87. writing to uncached memory. In my timing it seems to be about 10% faster than
  88. my loop and CopyBits on my 7500/100.
  89.  
  90. BlockMoveData is a variant of BlockMove that omits cache flushing. 
  91. It arrived in System Update 3.0 to System 7. Issuing BlockMoveData() on earlier versions
  92. of the operating system will invoke plain-old BlockMove(). BlockMoveData, like
  93. BlockMove, uses the MOVE16 instruction, on computers that have it, so it could
  94. potentially be faster than the generic code that most compilers produce.
  95. However, I didn't found any speed advantage on the PowerBook 170, Mac II, IIfx,
  96. and Power Mac in my lab (none of which have the 68040, which is the only cpu
  97. that has MOVE16). I haven't tried it on a Quadra. 
  98.  
  99. The use of BlockMoveData is disabled if the computer has a 68040
  100. processor, yet is a Mac II. I do this because BlockMoveData crashed on my Radius
  101. Rocket (68040 processor on a NuBus card) in my Mac II when handed addresses in
  102. video memory, even though MODE32 was installed. Presumably this indicates that
  103. the BlockMove routine was not 32-bit clean, despite the runtime patches installed
  104. by MODE32. This is puzzling since BlockMove works fine accessing the same video
  105. addresses in either 24 or 32-bit mode (with MODE32) without the Rocket.
  106.  
  107. Copyright ©1989-1996 Denis G. Pelli.
  108.  
  109. Received:    1/28/96 12:46 PM
  110.  
  111. "When is it safe to call BlockMoveDataUncached?"
  112.  
  113. This function is part of the PCI Driver Services Library and as such should not
  114. be called from an application.  To determine if the machine upon which your
  115. application is running, is PCI do the following.
  116.  
  117. You must first check if the NameRegistry exists.  There is a Gestalt Manager
  118. selector for
  119. this, 'nreg'.  If it exists, the value returned will be the version number (
  120. number 1 for now) of the Name Registry.  Otherwise, you should get a
  121. gestaltUndefSelectorErr. If the Name Registry does not exist then you should
  122. assume that it is not a PCI based machine.  At this point it can be NuBus or no
  123. bus at all.
  124.  
  125. You can use the Name Registry to determine if a PCI bus exists.  To do this you
  126. should use RegistryEntrySearch to locate an entry/node having a known
  127. property/value, propertyName = "devic-type", and propertyValue = "pci"  If an
  128. entry is found that has that known property/value (noErr and done = "False"),
  129. there is a PCI bus.
  130.  
  131. You do not need to worry about cache topology if you're a driver writer.  The
  132. newer MacOS(tm) removes this burden from the writer by supplying BlockCopy.  This
  133. function will always know the cache topology and forward your request to the
  134. appropriate copy routine.
  135.  
  136. Regards
  137.  
  138. Wayne Flansburg
  139. DTS
  140. Apple Computer
  141.  
  142. 3/19/96 dgp as advised by Wayne at apple, above, i tried replacing my call to BlockMoveData by
  143. BlockCopy, but BlockCopy runs ten time SLOWER (under System 7.5.3 on a 7500/100), 
  144. which defeats the purpose. Wayne notes that we can only use these traps
  145. on PCI Macs. Apparently when Copland comes they will be available solely to
  146. device drivers, which suggests that CopyBitsQuickly.c may then need to be implemented
  147. partly as a device driver.
  148.  
  149. >From elliott@mpi-muelheim.mpg.de (Mark Elliott)
  150. Subject: Direct-to-screen drawing and Copland
  151. Date: Thu, 14 Mar 1996 15:37:43 +0100
  152. Organization: Max-Planck-Institut f. Kohlenforsch. Muelheim
  153.  
  154. Hi All,
  155.  
  156. There has been a bit of debate about this, and I just got my latest
  157. developer mailing today, and here's the verdict.
  158.  
  159. (not an exact quote, but the content of the quote is specific)
  160.  
  161. 'Apple realises that some applications (specifically games are mentioned)
  162. NEED (my emphasis) direct-to-screen drawing. As long as you follow the
  163. guidelines set forth in the Develop article by Brigham Stevens (issue 11
  164. ?) then applications using this technique will still work under Copland
  165. (assuming you don't break any other rules, of course!)'.
  166.  
  167. What this means is locking PixMaps. Getting base address using
  168. GetPixBaseAddr(), etc.
  169.  
  170. I have not interpreted the text. It is all there in black and white. So
  171. one possible cause for game-programmers to worry about Copland is sorted.
  172.  
  173. hope this reassures you.
  174.  
  175. Mark
  176.  
  177. - ------------------------------------------------------------------
  178. Mark C Elliott                           elliott@mpi-muelheim.mpg.de
  179. Max-Planck-Institut                      voice: (+49) 208 306 2429
  180. Fuer Kohlenforschung
  181. Muelheim, Germany
  182. - ------------------------------------------------------------------
  183.  
  184. HISTORY:
  185. 1/89 dgp    Version 2.0: added support for PixMaps and multiple screens. Added checking.
  186. 6/89 dgp    Version 3.0: now use RectToAddress, which clips to one device.
  187. 10/89 dgp    Version 3.5: Improved resolution from longs to bytes.
  188. 10/89 dgp    Version 4.0: Added new mode: addOver
  189. 3/90  dgp    Version 4.01: Made cosmetic changes:
  190.             renamed srcRect & dstRect to srcRectPtr and dstRectPtr.
  191.             renamed srcAdd to addOver, to conform to CopyBits.
  192.             added a few more comments to explain the initial clipping.
  193. 3/20/90    dgp    made compatible with MPW C.
  194. 4/20/90    dgp    now uses 32-bit addressing only if QD32 is present.
  195. 4/9/91    dgp    v 4.05: changed nudge from short to long, just to be safe
  196. 8/24/91    dgp    Made compatible with THINK C 5.0.
  197. 4/15/92    dgp    Updated CopyBitsQuickly's function header to Standard C style.
  198. 10/5/92 dgp    Dropped support for THINK C 4. Updated the documentation above.
  199. 12/2/92 dgp cosmetic changes
  200. 12/8/92 dgp fixed major gaffe introduced on 12/2/92: "case" prefix was 
  201.             missing in switch statement. This caused CopyBitsQuickly to do nothing. 
  202. 1/31/93    dgp    Added new "multiplyQuickly" mode requested by Josh Solomon. Now 
  203.             insist on 8-bit pixels for both addOver and multiplyQuickly modes.
  204. 2/18/93    js    added mulOver to list of allowed modes. (Oops! - dgp.) Works ok now.
  205. 2/18/93    dgp    Now return int, nonzero if error occurred.
  206. 7/9/93    dgp check for 32-bit addressing capability.
  207. 6/5/94    dgp Replaced all assembly code by portable C code of similar speed. Only call 
  208.             SwapMMUMode() if we must. Give error if we need 32-bit mode and it's not 
  209.             available. Documented the returned value.
  210. 6/7/94    dgp    Added code to use Apple's BlockMoveData() for highest
  211.             possible speed on all Macs, but disabled it because it didn't turn
  212.             out to be faster on the machines on which I've tested it: Mac II, IIfx,
  213.             and Power Mac 6100/60.
  214. 6/7/94    dgp    Added new mode "addOverParallel" which accepts any pixelSize and adds
  215.             source to destination very quickly by adding 4 bytes at a time.
  216. 6/14/94    dgp    can32 is now computed by calling TrapAvailable(_SwapMMUMode), which 
  217.             returns the correct answer even on Macs with dirty ROMs.
  218. 5/23/95 dgp Apple changed the prototype in the header file from SwapMMUMode(char *) to 
  219.             SwapMMUMode(signed char *). To retain compatibility with both old and new
  220.             headers, I cast the argument (void *).
  221. 1/25/96 dgp Enabled use of BlockMoveData and BlockMoveDataUncached.
  222. 1/28/96 dgp only call BlockMoveDataUncached on PCI Macs; otherwise use BlockMoveData.
  223. 3/4/96 dgp made compatible with THINK C 7.
  224. */
  225. #include "VideoToolbox.h"
  226. void ReadPixels(int x,int y,int n,unsigned long *value
  227.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  228. void WritePixels(int x,int y,int n,unsigned long *value
  229.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  230. extern void BlockMoveUncached(const void *srcPtr, void *destPtr, Size byteCount);
  231. #if GENERATINGPOWERPC
  232. // BlockMoveDataUncached is only available on PowerPC. Apparently video buffers are "uncacheable" and
  233. // BlockMoveData uses an instruction that is emulated slowly in that case.
  234.     extern void BlockMoveDataUncached(const void *srcPtr, void *destPtr, Size byteCount);
  235.     extern void BlockCopy(const void *srcPtr, void *destPtr, Size byteCount);
  236. #else
  237.     #define BlockMoveDataUncached BlockMoveData
  238.     #define BlockCopy BlockMoveData
  239. #endif
  240. // The srcMode constants addOverParallel and mulOver are defined in VideoToolbox.h
  241. #ifndef __TRAPS__
  242.     #include <Traps.h>        // _SwapMMUMode
  243. #endif
  244. #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
  245.     // These THINK C options seem to have very little effect on the code produced.
  246.     // However, if you don't disable "assign_registers" then one of the variables
  247.     // declared "register" in srcCopyQuickly() fails to be assigned to a register.
  248.     #pragma options(!assign_registers,honor_register,redundant_loads,defer_adjust)
  249.     #pragma options(global_optimizer,gopt_induction,gopt_loop,gopt_cse,gopt_coloring)
  250. #endif
  251. #if UNIVERSAL_HEADERS>1
  252.     #ifndef __CODEFRAGMENTS__
  253.         #include <CodeFragments.h>
  254.     #endif
  255. #else
  256.     #undef NO_DRIVER_SERVICES_LIB
  257.     #define NO_DRIVER_SERVICES_LIB 1
  258. #endif
  259.  
  260. typedef unsigned char *UPtr;
  261.  
  262. static void Expand8(double hMag,double vMag,double hOffset,double vOffset
  263.     ,register UPtr Src,Rect *srcRect,unsigned long srcRowBytes
  264.     ,register UPtr Dst,Rect *dstRect,unsigned long dstRowBytes,Boolean do32);
  265. static void Expand(double hMag,double vMag,double hOffset,double vOffset
  266.     ,register UPtr Src,Rect *srcRect,int srcPixelBits,unsigned long srcRowBytes
  267.     ,register UPtr Dst,Rect *dstRect,int dstPixelBits,unsigned long dstRowBytes,Boolean do32);
  268. static void SrcCopyQuickly(UPtr Src,unsigned long srcinc,
  269.     UPtr Dst,unsigned long dstinc,
  270.     unsigned long bytes,unsigned long lines,Boolean do32);
  271. static void SrcCopyQuickly2(UPtr Src,unsigned long srcinc,
  272.     UPtr Dst,unsigned long dstinc,
  273.     unsigned long bytes,unsigned long lines,Boolean do32);
  274. static void AddOverParallel(UPtr Src,unsigned long srcinc,
  275.     UPtr Dst,unsigned long dstinc,
  276.     unsigned long bytes,unsigned long lines,Boolean do32);
  277. static void AddOver8(UPtr Src,unsigned long srcinc,
  278.     UPtr Dst,unsigned long dstinc,
  279.     unsigned long bytes,unsigned long lines,Boolean do32);
  280. static void MulOver8(UPtr Src,unsigned long srcinc,
  281.     UPtr Dst,unsigned long dstinc,
  282.     unsigned long bytes,unsigned long lines,Boolean do32);
  283.  
  284. static Boolean pci;    // Is this a PCI Mac? Only the PCI Macs have BlockMoveDataUncached.
  285.  
  286. int CopyBitsQuickly(BitMap *srcBits,BitMap *dstBits
  287.     ,Rect *srcRectPtr,Rect *dstRectPtr,long srcMode,RgnHandle maskRgn)
  288. {
  289.     UPtr Src,Dst;
  290.     long srcinc,dstinc;
  291.     unsigned long lines;
  292.     short srcRowBytes,dstRowBytes,srcPixelSize,dstPixelSize,srcBitsOffset,dstBitsOffset;
  293.     Rect mySrcRect,myDstRect;
  294.     int hOffset,vOffset;
  295.     double hMag,vMag;
  296.     long nudge,bytes;
  297.     Boolean do32,useBlockMove;
  298.     static Boolean can32,is32,wantBlockMove,firstTime=1;
  299.     long error,addressing,machine,processor,templong;
  300.  
  301.     srcMode&=0xffff;    // upper bits are used only by CopyWindows.
  302.     if(srcMode != srcCopy && srcMode != addOver && srcMode != addOverParallel && srcMode != mulOver)
  303.         return 1;
  304.     if(maskRgn != NULL) return 2;
  305.  
  306.     /* clip the rect to be copied by the bounds of source and destination */
  307.     mySrcRect=*srcRectPtr;
  308.     myDstRect=*dstRectPtr;
  309.  
  310.     hMag=(double)(myDstRect.right-myDstRect.left)/(mySrcRect.right-mySrcRect.left);
  311.     vMag=(double)(myDstRect.bottom-myDstRect.top)/(mySrcRect.bottom-mySrcRect.top);
  312.     if((vMag!=1 || hMag!=1) && srcMode!=srcCopy)return 3;
  313.     /* first make sure that srcRect and dstRect are the same size */
  314. //    if(mySrcRect.bottom-mySrcRect.top != myDstRect.bottom-myDstRect.top || 
  315. //        mySrcRect.right-mySrcRect.left != myDstRect.right-myDstRect.left) 
  316. //            return 3;
  317.  
  318.     hOffset=myDstRect.left-mySrcRect.left*hMag;
  319.     vOffset=myDstRect.top-mySrcRect.top*vMag;
  320.     /* clip myDstRect */
  321.     Dst = RectToAddress((PixMap *)dstBits,&myDstRect,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  322.  
  323.     /*
  324.     This prevents writing outside the destination.
  325.     The cost is that part of the inside will not be written.
  326.     The problem arises because this routine's code can only write whole bytes,
  327.     and the boundary may be in the middle of a byte. So, rather than writing an
  328.     extra fraction of a byte (outside the destination rect) we leave the byte
  329.     alone and fail to update a small portion inside the destination rect.
  330.     */
  331.     if(dstBitsOffset>0) {
  332.         nudge=(7+dstBitsOffset)/8;
  333.         dstBitsOffset -= nudge*8;
  334.         Dst += nudge;
  335.         myDstRect.left += nudge*8/dstPixelSize;
  336.     }
  337.  
  338.     /* Copy any clipping of myDstRect over to mySrcRect */
  339.     mySrcRect=myDstRect;
  340.     ExpandAndOffsetRect(&mySrcRect,1/hMag,1/vMag,-hOffset/hMag,-vOffset/vMag);
  341.     /* clip mySrcRect */
  342.     Src=RectToAddress((PixMap *)srcBits,&mySrcRect
  343.         ,&srcRowBytes,&srcPixelSize,&srcBitsOffset);
  344.  
  345.     /* Copy any clipping of mySrcRect back to myDstRect */
  346.     myDstRect=mySrcRect;
  347.     ExpandAndOffsetRect(&myDstRect,hMag,vMag,hOffset,vOffset);
  348.     Dst=RectToAddress((PixMap *)dstBits,&myDstRect
  349.         ,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  350.  
  351.     if(Src==NULL || Dst==NULL) return 4;
  352.     if(srcPixelSize != dstPixelSize && srcMode!=srcCopy) return 5;
  353.     bytes = mySrcRect.right - mySrcRect.left;    /* number of pixels per line */
  354.     bytes *= srcPixelSize;                        /* number of bits per line */
  355.     bytes /= 8;                                    /* number of bytes per line */
  356.     srcinc = srcRowBytes - bytes;                /* offset in bytes to beginning of next line */
  357.     dstinc = dstRowBytes - bytes;
  358.     lines=mySrcRect.bottom - mySrcRect.top;        /* number of lines */
  359.     if(srcinc==0 && dstinc==0){
  360.         bytes*=lines;
  361.         lines=1;
  362.     }
  363.     if(firstTime){
  364.         can32=TrapAvailable(_SwapMMUMode);
  365.         addressing=0;
  366.         error=Gestalt(gestaltAddressingModeAttr,&addressing);
  367.         is32=addressing&(1L<<gestalt32BitAddressing);
  368.         // BlockMoveDataUncached is fast, but needs the glue in DriverServicesLib.
  369.         wantBlockMove=1;
  370.         #if CFMSYSTEMCALLS
  371.             if(wantBlockMove){
  372.                 // The BlockMoveDataUncached glue is in a shared library.
  373.                 // If the DriverServicesLib is weak-linked, and missing, we need to
  374.                 // check for the library, to prevent a crash if we try to access the 
  375.                 // library's exports.
  376.                 CFragConnectionID        connID;
  377.                 Ptr                        mainAddr;
  378.                 Str255                    errName;
  379.                 long templong;
  380.                 
  381.                 error=Gestalt(gestaltCFMAttr,&templong);    // Code Fragment Manager?
  382.                 if(!error)error=GetSharedLibrary((ConstStr63Param)"\pDriverServicesLib"
  383.                     ,kAnyCFragArch,kFindCFrag,&connID,&mainAddr,errName);
  384.                 if(error)wantBlockMove=0;    // No DriverServicesLib
  385.     //            if(error)printf("\nGetSharedLibrary error=%d, %#s\n\007",(int)error, errName);
  386.             }
  387.         #endif
  388.         if(wantBlockMove){
  389.             // Crude test for Rocket accelerator in Mac II.
  390.             // BlockMove to or from a video address crashed my Radius Rocket.
  391.             error=Gestalt(gestaltProcessorType,&processor);
  392.             error=Gestalt(gestaltMachineType,&machine);
  393.             if(machine==gestaltMacII && processor==gestalt68040)wantBlockMove=0;
  394.         }
  395.         #define gestaltNameRegistryVersion 'nreg'    // support old Gestalt.h header
  396.         error=Gestalt(gestaltNameRegistryVersion,&templong);
  397.         pci=(error==0);    // are there PCI slots?
  398. //printf("\nwantBlockMove=%d\n\007",(int)wantBlockMove);
  399.         firstTime=0;
  400.     }
  401.     // Must we switch to 32-bit addressing?
  402.     do32=(unsigned long)Src>0xffffffUL || (unsigned long)Dst>0xffffffUL;
  403.     do32=do32 && !is32;
  404.     if(do32 && !can32)return 6;
  405.     // Can't use traps if we switch 24/32-bit mode.
  406.     useBlockMove=wantBlockMove && !do32 && srcPixelSize==dstPixelSize;
  407.  
  408.     switch(srcMode){
  409.     case srcCopy:
  410.         if(hMag!=1 || vMag!=1 || srcPixelSize != dstPixelSize){
  411.             if(srcPixelSize==8 && dstPixelSize==8)Expand8(hMag,vMag,hOffset,vOffset
  412.                 ,Src,&mySrcRect,srcRowBytes,Dst,&myDstRect,dstRowBytes,do32);
  413.             else Expand(hMag,vMag,hOffset,vOffset
  414.                 ,Src,&mySrcRect,srcPixelSize,srcRowBytes
  415.                 ,Dst,&myDstRect,dstPixelSize,dstRowBytes,do32);
  416.         } else if(useBlockMove)SrcCopyQuickly2(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  417.         else SrcCopyQuickly(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  418.         break;
  419.     case addOverParallel:
  420.         if(srcPixelSize!=dstPixelSize)return 5;
  421.         AddOverParallel(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  422.         break;
  423.     case addOver:
  424.         if(srcPixelSize!=8 || dstPixelSize!=8)return 7;
  425.         AddOver8(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  426.         break;
  427.     case mulOver:
  428.         if(srcPixelSize!=8 || dstPixelSize!=8)return 7;
  429.         MulOver8(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  430.         break;
  431.     default:
  432.         return 1;
  433.         break;
  434.     }
  435.     return 0;
  436. }
  437.  
  438. static void Expand8(double hMag,double vMag,double hOffset,double vOffset
  439.     ,register UPtr Src,Rect *srcRect,unsigned long srcRowBytes
  440.     ,register UPtr Dst,Rect *dstRect,unsigned long dstRowBytes,Boolean do32)
  441. {
  442.     int hh=round(hMag),vv=round(vMag);
  443.     int srcWidth,dstWidth;
  444.     register int i,j,ii;
  445.     register UPtr src,dst;
  446.     register unsigned char a;
  447.     signed char mmumode=true32b;
  448.  
  449.     hOffset;vOffset;dstRect;    /* unused arguments */
  450.     srcWidth=srcRect->right-srcRect->left;
  451.     dstWidth=srcWidth*hh;
  452.     for(j=srcRect->bottom-srcRect->top;j>0;j--){
  453.         src=Src;
  454.         dst=Dst;
  455.         if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  456.         for(i=srcWidth;i>0;i--){
  457.             a=*src++;
  458.             for(ii=hh;ii>0;ii--)*dst++=a;
  459.         }
  460.         if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  461.         src=Dst;
  462.         Dst+=dstRowBytes;
  463.         for(ii=vv-1;ii>0;ii--){
  464.             if(pci)BlockMoveDataUncached(src,Dst,dstWidth);
  465.             else BlockMoveData(src,Dst,dstWidth);
  466.             Dst+=dstRowBytes;
  467.         }
  468.         Src+=srcRowBytes;
  469.     }
  470. }    
  471.  
  472. static void Expand(double hMag,double vMag,double hOffset,double vOffset
  473.     ,register UPtr Src,Rect *srcRect,int srcPixelBits,unsigned long srcRowBytes
  474.     ,register UPtr Dst,Rect *dstRect,int dstPixelBits,unsigned long dstRowBytes,Boolean do32)
  475. {
  476.     int hh=round(hMag),vv=round(vMag);
  477.     long srcWidth,dstWidth,bytes;
  478.     register int i,j,ii;
  479.     register UPtr src;
  480.     signed char mmumode=true32b;
  481.     unsigned long value[1024],v,*srcV,*dstV;
  482.  
  483.     hOffset;vOffset;dstRect;do32;    /* unused arguments */
  484.     srcWidth=srcRect->right-srcRect->left;
  485.     dstWidth=srcWidth*hh;
  486.     bytes=dstWidth*dstPixelBits/8;
  487.     for(j=srcRect->bottom-srcRect->top;j>0;j--){
  488.         ReadPixels(0,0,srcWidth,value,Src,srcPixelBits,srcRowBytes);
  489.         srcV=value+srcWidth-1;
  490.         dstV=value+srcWidth*hh-1;
  491.         for(i=srcWidth;i>0;i--){
  492.             v=*srcV--;
  493.             for(ii=hh;ii>0;ii--)*dstV--=v;
  494.         }
  495.         WritePixels(0,0,dstWidth,value,Dst,dstPixelBits,dstRowBytes);
  496.         src=Dst;
  497.         Dst+=dstRowBytes;
  498.         for(ii=vv-1;ii>0;ii--){
  499.             if(pci)BlockMoveDataUncached(src,Dst,bytes);
  500.             else BlockMoveData(src,Dst,bytes);
  501.             Dst+=dstRowBytes;
  502.         }
  503.         Src+=srcRowBytes;
  504.     }
  505. }    
  506.  
  507. static void SrcCopyQuickly2(register UPtr Src,register unsigned long srcinc,
  508.     register UPtr Dst,register unsigned long dstinc,
  509.     unsigned long bytes,register unsigned long lines,Boolean do32)
  510. {
  511.     // See discussion of BlockMoveData at top of this file.
  512.  
  513.     do32;    /* dgp: prevent "unused argument" warning */
  514.     srcinc+=bytes;
  515.     dstinc+=bytes;
  516.     for(;lines>0;lines--){
  517.         if(pci)BlockMoveDataUncached(Src,Dst,bytes);
  518.         else BlockMoveData(Src,Dst,bytes);
  519.         Src+=srcinc;
  520.         Dst+=dstinc;
  521.     }
  522. }    
  523.  
  524. #define useMask 0
  525. static void SrcCopyQuickly(UPtr xSrc,register unsigned long srcinc,
  526.     UPtr xDst,register unsigned long dstinc,
  527.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  528. {
  529.     register unsigned long *SrcL=(unsigned long *)xSrc,*DstL=(unsigned long *)xDst;
  530.     register long i;
  531.     signed char mmumode=true32b;
  532.     static unsigned long mask32[4]={0,0xff,0xffff,0xffffff};
  533.     register unsigned long m=mask32[bytes&3];
  534.  
  535.     if(useMask){
  536.         srcinc+=bytes&3;
  537.         dstinc+=bytes&3;
  538.     }
  539.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  540.     for(;lines>0;lines--) {
  541.         i=bytes>>7;
  542.         switch((bytes>>2)&31){
  543.             for(;i>=0;i--){
  544.                             *DstL++ = *SrcL++;
  545.                 case 31:    *DstL++ = *SrcL++;
  546.                 case 30:    *DstL++ = *SrcL++;
  547.                 case 29:    *DstL++ = *SrcL++;
  548.                 case 28:    *DstL++ = *SrcL++;
  549.                 case 27:    *DstL++ = *SrcL++;
  550.                 case 26:    *DstL++ = *SrcL++;
  551.                 case 25:    *DstL++ = *SrcL++;
  552.                 case 24:    *DstL++ = *SrcL++;
  553.                 case 23:    *DstL++ = *SrcL++;
  554.                 case 22:    *DstL++ = *SrcL++;
  555.                 case 21:    *DstL++ = *SrcL++;
  556.                 case 20:    *DstL++ = *SrcL++;
  557.                 case 19:    *DstL++ = *SrcL++;
  558.                 case 18:    *DstL++ = *SrcL++;
  559.                 case 17:    *DstL++ = *SrcL++;
  560.                 case 16:    *DstL++ = *SrcL++;
  561.                 case 15:    *DstL++ = *SrcL++;
  562.                 case 14:    *DstL++ = *SrcL++;
  563.                 case 13:    *DstL++ = *SrcL++;
  564.                 case 12:    *DstL++ = *SrcL++;
  565.                 case 11:    *DstL++ = *SrcL++;
  566.                 case 10:    *DstL++ = *SrcL++;
  567.                 case 9:        *DstL++ = *SrcL++;
  568.                 case 8:        *DstL++ = *SrcL++;
  569.                 case 7:        *DstL++ = *SrcL++;
  570.                 case 6:        *DstL++ = *SrcL++;
  571.                 case 5:        *DstL++ = *SrcL++;
  572.                 case 4:        *DstL++ = *SrcL++;
  573.                 case 3:        *DstL++ = *SrcL++;
  574.                 case 2:        *DstL++ = *SrcL++;
  575.                 case 1:        *DstL++ = *SrcL++;
  576.                 case 0:;
  577.             }
  578.         }
  579.         if(useMask){
  580.             if(m) *DstL=(m & *SrcL) | (!m & *DstL);
  581.         }else{
  582.             if(bytes&2){
  583.                 *(unsigned short *)DstL=*(unsigned short *)SrcL;
  584.                 DstL=(unsigned long *)(1+(unsigned short *)DstL);
  585.                 SrcL=(unsigned long *)(1+(unsigned short *)SrcL);
  586.             }
  587.             if(bytes&1){
  588.                 *(unsigned char *)DstL=*(unsigned char *)SrcL;
  589.                 DstL=(unsigned long *)(1+(unsigned char *)DstL);
  590.                 SrcL=(unsigned long *)(1+(unsigned char *)SrcL);
  591.             }
  592.         }
  593.         DstL=(unsigned long *)(dstinc+(unsigned char *)DstL);
  594.         SrcL=(unsigned long *)(srcinc+(unsigned char *)SrcL);
  595.     }
  596.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  597. }
  598.  
  599. static void AddOverParallel(UPtr xSrc,register unsigned long srcinc,
  600.     UPtr xDst,register unsigned long dstinc,
  601.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  602. {
  603.     register unsigned long *SrcL=(unsigned long *)xSrc,*DstL=(unsigned long *)xDst;
  604.     register long i;
  605.     signed char mmumode;
  606.  
  607.     mmumode=true32b;
  608.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  609.     for(;lines>0;lines--) {
  610.         i=bytes>>7;
  611.         switch((bytes>>2)&31){
  612.             for(;i>=0;i--){
  613.                             *DstL++ += *SrcL++;
  614.                 case 31:    *DstL++ += *SrcL++;
  615.                 case 30:    *DstL++ += *SrcL++;
  616.                 case 29:    *DstL++ += *SrcL++;
  617.                 case 28:    *DstL++ += *SrcL++;
  618.                 case 27:    *DstL++ += *SrcL++;
  619.                 case 26:    *DstL++ += *SrcL++;
  620.                 case 25:    *DstL++ += *SrcL++;
  621.                 case 24:    *DstL++ += *SrcL++;
  622.                 case 23:    *DstL++ += *SrcL++;
  623.                 case 22:    *DstL++ += *SrcL++;
  624.                 case 21:    *DstL++ += *SrcL++;
  625.                 case 20:    *DstL++ += *SrcL++;
  626.                 case 19:    *DstL++ += *SrcL++;
  627.                 case 18:    *DstL++ += *SrcL++;
  628.                 case 17:    *DstL++ += *SrcL++;
  629.                 case 16:    *DstL++ += *SrcL++;
  630.                 case 15:    *DstL++ += *SrcL++;
  631.                 case 14:    *DstL++ += *SrcL++;
  632.                 case 13:    *DstL++ += *SrcL++;
  633.                 case 12:    *DstL++ += *SrcL++;
  634.                 case 11:    *DstL++ += *SrcL++;
  635.                 case 10:    *DstL++ += *SrcL++;
  636.                 case 9:        *DstL++ += *SrcL++;
  637.                 case 8:        *DstL++ += *SrcL++;
  638.                 case 7:        *DstL++ += *SrcL++;
  639.                 case 6:        *DstL++ += *SrcL++;
  640.                 case 5:        *DstL++ += *SrcL++;
  641.                 case 4:        *DstL++ += *SrcL++;
  642.                 case 3:        *DstL++ += *SrcL++;
  643.                 case 2:        *DstL++ += *SrcL++;
  644.                 case 1:        *DstL++ += *SrcL++;
  645.                 case 0:;
  646.             }
  647.         }
  648.         if(bytes&2){
  649.             *(unsigned short *)DstL += *(unsigned short *)SrcL;
  650.             DstL=(unsigned long *)(1+(unsigned short *)DstL);
  651.             SrcL=(unsigned long *)(1+(unsigned short *)SrcL);
  652.         }
  653.         if(bytes&1){
  654.             *(unsigned char *)DstL += *(unsigned char *)SrcL;
  655.             DstL=(unsigned long *)(1+(unsigned char *)DstL);
  656.             SrcL=(unsigned long *)(1+(unsigned char *)SrcL);
  657.         }
  658.         DstL=(unsigned long *)(dstinc+(unsigned char *)DstL);
  659.         SrcL=(unsigned long *)(srcinc+(unsigned char *)SrcL);
  660.     }
  661.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  662. }
  663.  
  664. static void AddOver8(register UPtr Src,register unsigned long srcinc,
  665.     register UPtr Dst,register unsigned long dstinc,
  666.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  667. {
  668.     register long i;
  669.     signed char mmumode;
  670.  
  671.     mmumode=true32b;
  672.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  673.     for(;lines>0;lines--) {
  674.         i=bytes>>5;
  675.         switch(bytes&31){
  676.             for(;i>=0;i--){
  677.                             *Dst++ += *Src++;
  678.                 case 31:    *Dst++ += *Src++;
  679.                 case 30:    *Dst++ += *Src++;
  680.                 case 29:    *Dst++ += *Src++;
  681.                 case 28:    *Dst++ += *Src++;
  682.                 case 27:    *Dst++ += *Src++;
  683.                 case 26:    *Dst++ += *Src++;
  684.                 case 25:    *Dst++ += *Src++;
  685.                 case 24:    *Dst++ += *Src++;
  686.                 case 23:    *Dst++ += *Src++;
  687.                 case 22:    *Dst++ += *Src++;
  688.                 case 21:    *Dst++ += *Src++;
  689.                 case 20:    *Dst++ += *Src++;
  690.                 case 19:    *Dst++ += *Src++;
  691.                 case 18:    *Dst++ += *Src++;
  692.                 case 17:    *Dst++ += *Src++;
  693.                 case 16:    *Dst++ += *Src++;
  694.                 case 15:    *Dst++ += *Src++;
  695.                 case 14:    *Dst++ += *Src++;
  696.                 case 13:    *Dst++ += *Src++;
  697.                 case 12:    *Dst++ += *Src++;
  698.                 case 11:    *Dst++ += *Src++;
  699.                 case 10:    *Dst++ += *Src++;
  700.                 case 9:        *Dst++ += *Src++;
  701.                 case 8:        *Dst++ += *Src++;
  702.                 case 7:        *Dst++ += *Src++;
  703.                 case 6:        *Dst++ += *Src++;
  704.                 case 5:        *Dst++ += *Src++;
  705.                 case 4:        *Dst++ += *Src++;
  706.                 case 3:        *Dst++ += *Src++;
  707.                 case 2:        *Dst++ += *Src++;
  708.                 case 1:        *Dst++ += *Src++;
  709.                 case 0:;
  710.             }
  711.         }
  712.         Src += srcinc;
  713.         Dst += dstinc;
  714.     }
  715.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  716. }
  717.  
  718. // Multiply two unsigned 8-bit pixels, and divide the product by 128.
  719. static void MulOver8(register UPtr Src,register unsigned long srcinc,
  720.     register UPtr Dst,register unsigned long dstinc,
  721.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  722. {
  723.     register long i;
  724.     signed char mmumode;
  725.  
  726.     mmumode=true32b;
  727.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  728.     for(;lines>0;lines--) {
  729.         i=bytes>>4;
  730.         switch(bytes&15){
  731.             for(;i>=0;i--){
  732.                             *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  733.                 case 15:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  734.                 case 14:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  735.                 case 13:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  736.                 case 12:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  737.                 case 11:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  738.                 case 10:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  739.                 case 9:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  740.                 case 8:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  741.                 case 7:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  742.                 case 6:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  743.                 case 5:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  744.                 case 4:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  745.                 case 3:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  746.                 case 2:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  747.                 case 1:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  748.                 case 0:;
  749.             }
  750.         }
  751.         Src += srcinc;
  752.         Dst += dstinc;
  753.     }
  754.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  755. }
  756.